package com.yuan.fmmall.service.Impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yuan.fmmall.dao.IndexImgMapper;
import com.yuan.fmmall.entity.IndexImg;
import com.yuan.fmmall.entity.ProductImg;
import com.yuan.fmmall.service.IndexImgService;
import com.yuan.fmmall.vo.ResStatus;
import com.yuan.fmmall.vo.ResultVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author Yuan
 */
@Service
public class IndexImgServiceImpl implements IndexImgService {
    @Autowired
    private IndexImgMapper indexImgMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public ResultVO listIndexImgs() {
        List<IndexImg> indexImgs = null;
        try {
            //尝试从redis中查询轮播图信息，可能查不到
            String imgsStr = stringRedisTemplate.boundValueOps("indexImgs").get();
            if (imgsStr != null) {
                //从redis中查询到轮播图信息
                //代码含义：将json字符串转换为ArrayList集合，
                JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, IndexImg.class);
                //readValue 方法可以将json字符串转换成指定的对象
                indexImgs = objectMapper.readValue(imgsStr, javaType);
            } else {
                //双重检测锁
                synchronized (this){
                    //再次查询redis（防止缓存击穿）
                    String s = stringRedisTemplate.boundValueOps("indexImgs").get();
                    if (s==null){
                        //高并发访问的第一次访问会进入此处
                        indexImgs = indexImgMapper.listIndexImgs();
                        if(indexImgs!=null){
                            stringRedisTemplate.boundValueOps("indexImgs").set(objectMapper.writeValueAsString(indexImgs));
                            stringRedisTemplate.boundValueOps("indexImgs").expire(1, TimeUnit.DAYS);
                        }else {
                            //防止缓存穿透
                            List<IndexImg> nullImgsList = new ArrayList<>();
                            stringRedisTemplate.boundValueOps("indexImgs").set(objectMapper.writeValueAsString(nullImgsList));
                            stringRedisTemplate.boundValueOps("indexImgs").expire(10, TimeUnit.SECONDS);
                        }
                    }else {
                        //高并发对同一资源的后续访问会进入这，即后续会直接从redis中查找数据
                        JavaType javaType = objectMapper.getTypeFactory().constructParametricType(ArrayList.class, IndexImg.class);
                        indexImgs = objectMapper.readValue(s, javaType);
                    }
                }
            }
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

        if (indexImgs!=null){
            return new ResultVO(ResStatus.OK,"success",indexImgs);
        }else {
            return new ResultVO(ResStatus.NO,"fail",null);
        }

    }
}
